package com.heima.juc.unlock;

import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * @author : leimingchao
 * @date Date : 2022年02月12日 19:58
 */
@Slf4j(topic = "c.Test5")
public class Test5 {

    public static void main(String[] args) {
        demo(() -> new int[10], array -> array.length, (array, index) -> array[index]++,array -> System.out.println(Arrays.toString(array)));

        demo(() -> new AtomicIntegerArray(10), array -> array.length(), (array, index) -> array.getAndIncrement(index), System.out::println);
    }

    /**
     *
     * @param arraySupplier 提供数组，可以是线程不安全数组或线程安全数组
     * @param lengthFun 获取数组长度的方法
     * @param putConsumer 自增方法，回传array,index
     * @param printConsumer 打印数组的方法
     * @param <T>
     */
    private static <T> void demo(Supplier<T> arraySupplier, Function<T, Integer> lengthFun, BiConsumer<T, Integer> putConsumer, Consumer<T> printConsumer) {

        List<Thread> ts = new ArrayList<>();
        T array = arraySupplier.get();
        int length = lengthFun.apply(array);

        for (int i = 0; i < length; i++) {

            //每个线程对数组作10000次操作
            ts.add(new Thread(() -> {
                for (int j = 0; j < 10000; j++) {
                    putConsumer.accept(array, j % length);
                }
            }));
        }

        // 启动所有线程
        ts.forEach(Thread::start);

        // 等所有线程结束
        ts.forEach(t -> {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        printConsumer.accept(array);
    }
}
